package com.snail.common.job.annotation;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONArray;
import com.snail.common.job.constant.JobConstants;
import com.snail.common.job.context.JobContextHolder;
import com.snail.job.admin.core.model.XxlJobInfo;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.SneakyThrows;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: job扫描注册
 * @Author: Snail
 * @CreateDate: 2024/9/18
 * @Version: V1.0
 */
public class JobScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {


    @SneakyThrows
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        try {
            AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(JobRegistrarScan.class.getName()));
            if (mapperScanAttrs == null) {
                return;
            }
            // 获取需要扫描的包
            String classPackage = mapperScanAttrs.getString("value");
            // 根据配置注解扫描包路径查找下面的类
            List<File> classFiles = findAllClasses(classPackage);
            if (CollUtil.isEmpty(classFiles)) {
                return;
            }

            List<XxlJobInfo> jobInfos = new ArrayList<>();
            for (int i = 0; i < classFiles.size(); i++) {
                File classFile = classFiles.get(i);
                String className = classFile.getName().substring(0, classFile.getName().length() - 6); // 6 is length of ".class"
                Class<?> aClass = Class.forName(classPackage + "." + className);
                Method[] methods = aClass.getMethods();
                for (Method method : methods) {
                    JobTask jobTask = method.getAnnotation(JobTask.class);
                    if (jobTask == null) {
                        continue;
                    }
                    XxlJob xxlJob = method.getAnnotation(XxlJob.class);
                    if (xxlJob == null) {
                        continue;
                    }
                    XxlJobInfo jobTaskInfo = buildJobInfo(xxlJob, jobTask);
                    jobInfos.add(jobTaskInfo);
                }
            }
            if (CollUtil.isNotEmpty(jobInfos)) {
                JobContextHolder.set(JobConstants.LOCAL_KEY_JOB_INFO, JSONArray.toJSONString(jobInfos));
            }
        } catch (Exception e) {
            throw new Exception("JobScannerRegistrar register fail:" + e.getMessage());
        }
    }

    private static XxlJobInfo buildJobInfo(XxlJob xxlJob, JobTask jobTask) {
        XxlJobInfo jobTaskInfo = new XxlJobInfo();
        jobTaskInfo.setExecutorHandler(xxlJob.value());
        jobTaskInfo.setScheduleConf(jobTask.cron());
        jobTaskInfo.setJobDesc(jobTask.value());
        jobTaskInfo.setExecutorRouteStrategy(jobTask.routeStrategy().name());
        jobTaskInfo.setExecutorBlockStrategy(jobTask.blockStrategy().name());
        jobTaskInfo.setAuthor(jobTask.auth());
        jobTaskInfo.setScheduleType(jobTask.scheduleType().name());
        jobTaskInfo.setGlueType(jobTask.glueType().name());
        jobTaskInfo.setMisfireStrategy(jobTask.misfireStrategy().name());
        jobTaskInfo.setTriggerStatus(1);
        return jobTaskInfo;
    }

    /**
     * 查找包下所有类
     *
     * @param classPackage 需要扫描的包
     * @return 所有类
     */
    private static List<File> findAllClasses(String classPackage) {

        List<File> files = new ArrayList<>();
        // 加载包路径
        URL url = ClassLoader.getSystemClassLoader().getResource(classPackage.replace(".", "/"));
        if (url == null) {
            return files;
        }
        // 加载文件
        File packageDir = new File(url.getFile());
        // 获取所有的class类
        File[] classFiles = packageDir.listFiles(file -> file.getName().endsWith(".class") && !file.isDirectory());
        if (classFiles != null && classFiles.length > 0) {
            files.addAll(Arrays.stream(classFiles).collect(Collectors.toList()));
        }
        return files;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {

    }
}
